#pragma once

#include <iostream>
#include <pthread.h>
#include <queue>
#include <vector>
#include <string>

static const int defaultnum = 5;

class ThreadInfo
{
public:
    pthread_t tid;
    std::string threadname;
};

template <class T>
class SingletonThreadPool
{
    void Lock()
    {
        pthread_mutex_lock(&lock);
    }
    void UnLock()
    {
        pthread_mutex_unlock(&lock);
    }
    void Wait()
    {
        pthread_cond_wait(&cond, &lock);
    }

    void WakeUp()
    {
        pthread_cond_signal(&cond);
    }

    bool IsEmptyThreadPool()
    {
        return _tasksqueue.size() == 0;
    }


public:
    static void* RoutineTasks(void* args)
    {
        SingletonThreadPool<T> *TP = static_cast<SingletonThreadPool<T>*>(args);

        while(true)
        {
            std::string name = TP->GetThreadName(pthread_self());
            TP->Lock();
            if(TP->IsEmptyThreadPool())
            {
                TP->Wait();
            }

            T t = TP->pop();
            TP->UnLock();

            t();

            std::cout << name << ' ' << std::endl;
            t.GetTask();

        }
    }

public:
    
    void ThreadStart()
    {
        int num = _threads.size();
        for(int i = 0; i < num; i++)
        {
            pthread_create(&_threads[i].tid, nullptr, RoutineTasks, this);
            _threads[i].threadname = "thread-" + std::to_string(i);
        }
    }

    T pop()
    {
        T task = _tasksqueue.front();
        _tasksqueue.pop();

        return task;
    }

    std::string GetThreadName(pthread_t tid)
    {
        for(const auto& e : _threads)
        {
            if(tid == e.tid)
            return e.threadname;
        }

        return "none";
    }

    void push(const T& task)
    {
        Lock();
        _tasksqueue.push(task);
        WakeUp();
        UnLock();
    }

    static SingletonThreadPool<T>* GetInStance()
    {
        //避免占用CPU和操作系统资源，做无意义的事，提高效率
        if(inst == nullptr)
        {
            //避免多线程模式下，同时申请多个inst
            pthread_mutex_lock(&slock);
            if(inst == nullptr)
            {
                inst = new SingletonThreadPool<T>;
            }
            pthread_mutex_unlock(&slock);
        }

        return inst;
    }

private:
    SingletonThreadPool(int num = defaultnum):_threads(num)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);
    }

    ~SingletonThreadPool()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }

    //防拷贝
    SingletonThreadPool(const SingletonThreadPool<T>& STP) = delete;
    SingletonThreadPool<T>& operator=(const SingletonThreadPool<T>& STP) = delete;

private:
    std::vector<ThreadInfo> _threads;
    std::queue<T> _tasksqueue;
    
    pthread_mutex_t lock;
    pthread_cond_t cond;

    static SingletonThreadPool<T> *inst;
    static pthread_mutex_t slock;
}; 

template<class T>
SingletonThreadPool<T>* SingletonThreadPool<T>::inst = nullptr;

template<class T>
pthread_mutex_t SingletonThreadPool<T>::slock = PTHREAD_MUTEX_INITIALIZER;
